package tool

import (
	"bytes"
	"encoding/json"
	"errors"
	"github.com/gorilla/websocket"
	"io"
	"log"
	"mime/multipart"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var client = &http.Client{
	Timeout: 30 * time.Second,
}

// 获取websocket拨号器,判断代理
func GetWebsocketDialer(serverURL string) *websocket.Dialer {
	dialer := websocket.DefaultDialer
	proxy := os.Getenv("GO_HTTP_PROXY")
	if len(proxy) > 0 && !httpIsInnerNet(serverURL) {
		p, _ := url.Parse(proxy)
		dialer.Proxy = http.ProxyURL(p)
		log.Printf("GetWebsocketDialer使用代理服务: %v\n", serverURL)
	}
	return dialer
}

func setHeaders(request *http.Request, headers map[string]string) {
	if headers != nil && len(headers) > 0 {
		for k, v := range headers {
			request.Header.Set(k, v)
		}
	}
}

func httpIsInnerNet(host string) bool {
	return strings.HasPrefix(host, "localhost") ||
		strings.HasPrefix(host, "127.") ||
		strings.HasPrefix(host, "172.") ||
		strings.HasPrefix(host, "192.") ||
		strings.HasSuffix(host, ".petrochina") ||
		strings.HasSuffix(host, ".internal") ||
		strings.HasSuffix(host, ".cnpc") ||
		host == "0.0.0.0" ||
		strings.HasPrefix(host, "10.") ||
		strings.HasPrefix(host, "11.")
}

func Do(request *http.Request) ([]byte, int, error) {
	var contents []byte

	proxy := os.Getenv("GO_HTTP_PROXY")

	if len(proxy) > 0 && !httpIsInnerNet(request.Host) {
		proxyURL, _ := url.Parse(proxy)
		client.Transport = &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
		}
	} else {
		client.Transport = nil
	}

	resp, err := client.Do(request)
	if err != nil {
		return contents, -1, err
	}
	defer resp.Body.Close()
	contents, err = io.ReadAll(resp.Body)
	if err != nil {
		return contents, resp.StatusCode, err
	}

	return contents, resp.StatusCode, nil
}

// HttpPost 普通POST请求
func HttpPost(url string, body []byte, headers map[string]string) ([]byte, int, error) {
	request, _ := http.NewRequest("POST", url, bytes.NewBuffer(body))
	setHeaders(request, headers)
	return Do(request)
}

// HttpPostJson POST JSON
func HttpPostJson(url string, post any, headers map[string]string) ([]byte, int, error) {
	postData, _ := json.Marshal(post)
	request, _ := http.NewRequest("POST", url, bytes.NewBuffer(postData))
	request.Header.Set("Content-Type", "application/json")
	setHeaders(request, headers)
	return Do(request)
}

func HttpGet(url string, params url.Values, headers map[string]string) ([]byte, int, error) {
	query := ""
	if params != nil {
		query = "?" + params.Encode()
	}
	request, _ := http.NewRequest("GET", url+query, nil)
	setHeaders(request, headers)
	return Do(request)
}

// httpSetMultiBody 设置multipart 请求体。
// 注意： writer 必须在client.Do之前关闭，不然服务端会报错：multipart: NextPart: EOF
func httpSetMultiBody(fileArr [][]string, bytesArr [][]byte, otherFields map[string]string) (*bytes.Buffer, string, error) {
	requestBody := &bytes.Buffer{}
	writer := multipart.NewWriter(requestBody)
	defer writer.Close()

	if fileArr != nil && len(fileArr) > 0 {
		for k, f := range fileArr {
			// 创建一个文件字段
			part, err := writer.CreateFormFile(f[0], filepath.Base(f[1]))
			if err != nil {
				return nil, "", errors.New("HttpPostMultipart 创建文件字段出错:" + err.Error())
			}

			// 将文件内容复制到请求体中
			_, err = io.Copy(part, bytes.NewReader(bytesArr[k]))
			if err != nil {
				return nil, "", errors.New("HttpPostMultipart 将文件内容复制到请求体出错:" + err.Error())
			}

		}
	}
	if otherFields != nil && len(otherFields) > 0 {
		for k, val := range otherFields {
			part, err := writer.CreateFormField(k)
			if err != nil {
				return nil, "", errors.New("HttpPostMultipart 创建普通字段出错:" + err.Error())
			}
			part.Write([]byte(val))
		}
	}

	return requestBody, writer.FormDataContentType(), nil
}

// HttpPostMultipart 发送 form/multipart 请求，可以发送多个文件
func HttpPostMultipart(url string, fileArr [][]string, bytesArr [][]byte, otherFields map[string]string, headers map[string]string) ([]byte, int, error) {
	requestBody, contentType, err := httpSetMultiBody(fileArr, bytesArr, otherFields)
	if err != nil {
		return nil, -1, err
	}
	if headers == nil {
		headers = make(map[string]string)
	}
	request, _ := http.NewRequest("POST", url, requestBody)
	headers["Content-Type"] = contentType
	setHeaders(request, headers)
	return Do(request)
}
